package com.af.security.configurer;

import com.af.security.auth.user.detail.AfUserDetails;
import com.github.benmanes.caffeine.cache.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

/**
 * @author : zhenyun.su
 * @comment : 直接使用caffeine
 * @since : 2021/6/24
 *  @EnableCaching ，开启cache注解，已支持@Cacheable 等
 *  Caffeine加载策略
 *      按条目总数，按权重，按过期策略，按引入策略来实现
 *  cache基本操作用法
 * 		Cache<String, Object> cache = Caffeine.newBuilder().build();
 * 		cache.put("key1", "value1");   key, value 都不能为空，否则NullPointerException
 * 		cache.put("key2", "value2");
 * 		Object object1= cache.getIfPresent("key1"); 按key1获取值，不存在返回null
 * 	    按list获取值map，不存在返回size=0的map，而不是null
 * 		Map<String, Object> allObject1= cache.getAllPresent(Arrays.asList("key1", "key2"));

 *      key3存在则取值，不存在则调用getValue方法获取值，写入cache并返回值，若getValue返回null，则直接返回null，不会写入cache
 *      需要注意： get的function参数不能为空，否则NullPointerException异常
 * 		Object object3= cache.get("key3",  key-> getValue(key));
 *      原理同上，区别按列表方式返回，若为空则返回size为0的map
 * 		Map<String, Object> allObject3= cache.getAll(Arrays.asList("key3", "key4"),  keys-> getValues((Iterable<String>) keys));

 * 	    public static Object getValue(String key){ return "value"; }
 * 	    public static Map<String, Object> getValues(Iterable<String> keys){
 * 		    Map<String, Object> map = new HashMap<>();
 * 		    for (String s : keys) {
 * 			   map.put(s, "value11");
 *          }
 * 		    return map;
 * 		}
 *
 *      删除条目
 *      cache.invalidate("key2");
 * 		cache.invalidate(Arrays.asList("keEnabkey3"));
 * 		cache.invalidateAll();
 */

@Configuration
@EnableCaching
public class AfCacheConfigurer {

    @Value("${asu.security.cacheExpired:60}")
    private Integer cacheExpired;

    @Bean("cacheManager")
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .recordStats()
                // 设置最后一次写入或访问后经过固定时间过期
                .expireAfterAccess(60, TimeUnit.SECONDS)
                // 初始的缓存空间大小
                .initialCapacity(100)
                // 缓存的最大条数
                .maximumSize(1000));
        return cacheManager;
    }

    /*
     * @comment : 60分钟过期，最大个数1W条
     */
    @Bean("securityCache")
    public Cache<String, AfUserDetails> securityCache(){
        return Caffeine.newBuilder()
                .recordStats()
                .initialCapacity(50)
                .maximumSize(10000)
                .expireAfterAccess(cacheExpired, TimeUnit.MINUTES)
                .build();
    }

    /*
     * @comment : 测试使用， 20秒过期，最大个数1W条
     */
    @Bean("securityCacheDev")
    public Cache<String, AfUserDetails> securityCacheDev(){
        return Caffeine.newBuilder()
                .recordStats()
                .initialCapacity(1)
                .maximumSize(2)
                .expireAfterAccess(20, TimeUnit.SECONDS)
                .build();
    }

    @Bean("userCache")
    public Cache<Integer, Object> userCache(){
        return Caffeine.newBuilder()
//                .recordStats()
                .initialCapacity(5)
                .maximumSize(100)
                // .removalListener(removalListener)
                .recordStats()
                .build();
    }
//
//     @Bean("weigherCache")
//     public LoadingCache<String, String> weigherCache(){
//         return Caffeine.newBuilder()
// //                .recordStats()
//                 .maximumWeight(1000)
//                 .weigher(weigher)
//                 .build(cacheLoader);
//     }
//

//
//     @Bean("weakCache")
//     public LoadingCache<String, Object> weakCache(){
//         return Caffeine.newBuilder()
// //                .recordStats()
// //                .softValues()
//                 .weakKeys()
//                 .weakValues()
//                 .build(cacheLoader);
//     }

}
